package frontend;

import org.eclipse.swt.internal.ole.win32.TYPEATTR;
import org.eclipse.swt.ole.win32.*;
import org.eclipse.swt.widgets.*;
import java.util.*;

public class WMPlayer {

	// fields
	private OleFrame frame;
	private OleClientSite site;
	private OleAutomation control;
	
	// methods
	public WMPlayer(Composite parent, int frameStyle, int siteStyle){
		this.frame = new OleFrame(parent, frameStyle);
		this.site = new OleClientSite(frame, siteStyle, "WMPlayer.OCX");
		this.site.doVerb(OLE.OLEIVERB_INPLACEACTIVATE);
	}
	
	public OleFrame getFrame(){
		return frame;
	}
	
	public OleClientSite getSite(){
		return site;
	}
	
	public void setVideo(String fileName){
		OleAutomation player = new OleAutomation(this.site);
		int playURL[] = player.getIDsOfNames(new String[] { "URL" });
		if (playURL != null) {
			Variant theFile = new Variant(fileName);
			player.setProperty(playURL[0], theFile);
		}
		try {
			// Get the "controls" variant of the video
			int controlId = player.getIDsOfNames(
					new String[]{"controls"})[0];
			Variant controlVar = player.getProperty(controlId);
			
			// Get the OleAutomation controlled by the "controls" Variant 
			// [REMEMBER: the "player" is not the OleAutomation controlled by 
			// the "controls" Variant, but that by the OleClientSite. The 
			// OleAutomation controlled (referred to) by the "controls" Variant 
			// is "control". And "control" contains Variant's of video actions]
			this.control = controlVar.getAutomation();
			controlVar.dispose();
		}catch (NullPointerException e){
		}catch (IndexOutOfBoundsException e){			
		}catch (NumberFormatException e){
		}
		player.dispose();
	}
	
	/**
	 * Get the current video time stamp [0 as the beginning of the video]
	 * @return
	 */
	public double getVideoTime(){
		double result = 0;
		try{
			int actId = 
				control.getIDsOfNames(
						new String[]{"currentPosition"})[0];
			Variant act = control.getProperty(actId);
			result = act.getDouble();
			act.dispose();
		}catch (NullPointerException e){			
		}catch (IndexOutOfBoundsException e){			
		}catch (NumberFormatException e){
		}
		return result;
	}
	
	/**
	 * Go to the certain time stamp in the video.
	 * @param point
	 */
	public void goTo(double point){
		try{
			this.pauseVideo();
			int actId = 
				control.getIDsOfNames(
						new String[]{"currentPosition"})[0];
			control.setProperty(actId, new Variant(point));
			this.playVideo();
			this.pauseVideo();
		}catch (NullPointerException e){			
		}catch (IndexOutOfBoundsException e){			
		}catch (NumberFormatException e){
		}
	}
	
	/**
	 * Go to the next step of the video.
	 */
	public void forward(double step){
		try{
			int actId = 
				control.getIDsOfNames(
						new String[]{"currentPosition"})[0];
			double cur = control.getProperty(actId).getDouble();
			control.setProperty(actId, new Variant(cur + step));
		}catch (NullPointerException e){			
		}catch (IndexOutOfBoundsException e){			
		}catch (NumberFormatException e){
		}
	}
	
	/**
	 * Go to the previous step of video.
	 */
	public void backward(double step){
		try{
			int actId = 
				control.getIDsOfNames(
						new String[]{"currentPosition"})[0];
			double cur = control.getProperty(actId).getDouble();
			control.setProperty(actId, new Variant(cur - step));
		}catch (NullPointerException e){			
		}catch (IndexOutOfBoundsException e){			
		}catch (NumberFormatException e){
		}
	}
	
	/**
	 * Stop the video.
	 */
	public void stopVideo(){
		try{
			int actId = 
				control.getIDsOfNames(
						new String[]{"stop"})[0];
			control.invoke(actId);
		}catch (NullPointerException e){			
		}catch (IndexOutOfBoundsException e){			
		}catch (NumberFormatException e){
		}
	}
	
	/**
	 * Pause the video.
	 */
	public void pauseVideo(){
		try{			
			int actId = 
				control.getIDsOfNames(
						new String[]{"pause"})[0];
			control.invoke(actId);
		}catch (NullPointerException e){			
		}catch (IndexOutOfBoundsException e){			
		}catch (NumberFormatException e){
		}
	}
	
	/**
	 * Play the video.
	 */
	public void playVideo(){
		try{
			int actId = 
				control.getIDsOfNames(
						new String[]{"play"})[0];
			control.invoke(actId);
		}catch (NullPointerException e){			
		}catch (IndexOutOfBoundsException e){			
		}catch (NumberFormatException e){
		}
	}
	
	/**
	 * Return a hash table from dispIDs to control property names, up to the
	 * specified maxID.
	 *  
	 * @param maxID
	 * @return
	 */
	public Hashtable<Integer, String> getControlPropertyNames(
			int maxID){
		Hashtable<Integer, String> result = 
			new Hashtable<Integer, String>();
		if (this.control != null){
			for (int i = 1; i <= maxID; i ++){
				String name = this.control.getName(i);
				if (name != null){
					result.put(new Integer(i), name);
				}
			}
		}
		return result;
	}
	
	/**
	 * Return a list of control properties.
	 * 
	 * @param maxID
	 * @return
	 */
	public String listControlPropertyNames(int maxID){
		String list = "";
		if (this.control != null){
			for (int i = 1; i <= maxID; i ++){
				String name = this.control.getName(i);
				if (name != null){
					list += i+": "+name+"\n";
				}
			}
		}
		return list;
	}

	/**
	 * List the properties of the site.
	 * @param maxID
	 * @return
	 */
	public String listSitePropertyNames(int maxID){
		String list = "";
		OleAutomation player = new OleAutomation(this.site);
		if (player != null){
			for (int i = 1; i <= maxID; i ++){
				String name = player.getName(i);
				if (name != null){
					list += i+": "+name+"\n";
				}
			}
		}
		player.dispose();
		return list;
	}
	
	public String getMediaTypeInfo(){
		TYPEATTR info = this.control.getTypeInfoAttributes();
		return info.toString();
	}
	
	/**
	 * Get a control property in string.
	 * 
	 * @param propName
	 * @return
	 */
	public String getProperty(String propName){
		int dispID = this.control.getIDsOfNames(
				new String[]{propName})[0];
		return this.control.getProperty(dispID).toString();
	}
	
	/**
	 * Determine if a valid video is given.
	 * @return
	 */
	public boolean hasVideo(){
		return (this.control!=null);
	}
	
	/**
	 * Set a control property.
	 * @param propName
	 * @param var
	 */
	public void setProperty(String propName, Variant var){
		int dispID = this.control.getIDsOfNames(
				new String[]{propName})[0];
		this.control.setProperty(dispID, var);
	}
	
	/**
	 * Invoke a property.
	 * 
	 * @param propName
	 */
	public void invokeProperty(String propName){
		int dispID = this.control.getIDsOfNames(
				new String[]{propName})[0];
		this.control.invoke(dispID);
	}
}
